#Python library imports
import re
#External libraries imports
from pyparsing import *
#Internal imports
from FSPPreprocessor import ConstantIdentifier, UppercaseIdentifier, LowercaseIdentifier
from ParsingUtilities import strJoin
__all__ = ("Expression")

def chain(ex, op, act):
  parser = ex + ZeroOrMore(Or([(Literal(o) + ex) for o in op]))
  return parser.setParseAction(act) if act else parser

def tree(p): return p[0] if len(p) == 1 else chain(tree(p[1:]), p[0][0], p[0][1])

Expression = Forward()

Integer = Word(nums)

BaseExpression =\
  (Integer ^ ConstantIdentifier.copy().setParseAction(lambda x: str(x[0])) ^
   LowercaseIdentifier.copy().setParseAction(lambda x: "{" + x[0] + "}") ^
   (Literal("(") + Expression + Literal(")")).setParseAction(strJoin))

Factor = ((Optional(Literal("+")) + BaseExpression) ^
                   (Literal("-") + BaseExpression) ^
                   (Literal("!") + BaseExpression)
                   .setParseAction(lambda u: u if re.match(variableRegex, u[1])
                                               else str(int(not eval(u[1])))))

variableRegex = re.compile(".*\{.*\}.*")

def andOrImplementation(x, operation):
  for term in x:
    if re.match(variableRegex, term): return strJoin(x)
  x = [eval(i) for i in [j for j in x if j != "&&" and j != "||"]]
  if len(x) == 1: return str(int(x[0]))
  return str(int(any(x) if operation == "or" else all(x)))


Expression << tree([[["||"], lambda x: andOrImplementation(x, "or")],
                    [["&&"], lambda x: andOrImplementation(x, "and")],
                    [["|"], strJoin], [["^"], None], [["&"], None],
                    [["==", "!="], None], [["<", "<=", ">", ">="], None],
                    [["<<", ">>"], None], [["+", "-"], None],
                    [["*", "/", "%"], None], Factor])
